#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
#define TNUM 5
typedef void (*func_t)(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond);

volatile bool quit = false;

/*
    全局写法：
    pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
*/



class ThreadData{
public:
    ThreadData(const std::string &name, func_t func, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
        :_name(name),_func(func),_pmtx(pmtx),_pcond(pcond)
        {

        }
public:
    std::string _name;
    func_t _func;
    pthread_mutex_t *_pmtx;
    pthread_cond_t *_pcond;
};

void f1(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond){
    while(!quit){
        // 条件等待【检测资源不就绪的情形】
        // 注意：wait 一定要在加锁与解锁之间！
        // 参数1：条件变量；参数2：互斥锁；
        pthread_mutex_lock(pmtx);               // 加锁
        pthread_cond_wait(pcond, pmtx);     
        // 默认该线程在执行的时候，wait代码被执行，当前线程会被立即阻塞
        std::cout << name << " is running ...  a" << std::endl;
        pthread_mutex_unlock(pmtx);             // 解锁
    }
}

void f2(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond){
    while(!quit){
        pthread_mutex_lock(pmtx);               // 加锁
        pthread_cond_wait(pcond, pmtx);     
        std::cout << name << " is running ...  b" << std::endl;
        pthread_mutex_unlock(pmtx);             // 解锁

    }
}

void f3(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond){
    while(!quit){
        pthread_mutex_lock(pmtx);               // 加锁
        pthread_cond_wait(pcond, pmtx);     
        std::cout << name << " is running ...  c" << std::endl;
        pthread_mutex_unlock(pmtx);             // 解锁

    }
}

void f4(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond){
    while(!quit){
        pthread_mutex_lock(pmtx);               // 加锁
        pthread_cond_wait(pcond, pmtx);     
        std::cout << name << " is running ...  d" << std::endl;
        pthread_mutex_unlock(pmtx);             // 解锁

    }
}

void f5(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond){
    while(!quit){
        pthread_mutex_lock(pmtx);               // 加锁
        pthread_cond_wait(pcond, pmtx);     
        std::cout << name << " is running ...  e" << std::endl;
        pthread_mutex_unlock(pmtx);             // 解锁

    }
}

void *Empty(void* args){
    ThreadData *td = (ThreadData*)args;         // 局部变量，td 在每一个线程自己私有的栈空间中保存！
    td->_func(td->_name, td->_pmtx, td->_pcond);                       // 它是一个函数，调用完成就要返回！
    delete td;
    return nullptr;
}


int main(){
    /* 实现主线程有序启动子线程 */

    pthread_mutex_t mtx;                    // 声明线程锁
    pthread_cond_t cond;                    // 声明条件变量
    pthread_mutex_init( &mtx, nullptr);     // 初始化线程锁
    pthread_cond_init( &cond, nullptr);     // 初始化条件变量


    pthread_t t[TNUM];
    func_t funcs[TNUM] = {f1,f2,f3,f4,f5};

    for(int i = 0;i<TNUM;i++){
        std::string name = "Thread ";
        name += std::to_string(i);
        ThreadData *td = new ThreadData(name, funcs[i], &mtx, &cond);
        pthread_create( t+i, nullptr, Empty, (void*)td);
    }

    sleep(3);

    // 线程控制（条件有序）
    int cnt = 10;

    while(cnt){
        std::cout << "Resume thread run code ... " << cnt-- <<  std::endl;
        // 唤醒在指定条件变量下等待的线程
        // pthread_cond_signal( &cond );       // 将条件变量从 无效 => 有效【每次唤醒一个】
        pthread_cond_broadcast( &cond );    // 一次性全部唤醒
        sleep(1);
    }

    std::cout << "ctrl done" << std::endl;
    quit = true;
    pthread_cond_broadcast( &cond );    // 一次性全部唤醒


    for(int i = 0;i<TNUM;i++){
        pthread_join(t[i], nullptr);
        std::cout << "Thread " << t[i] << " quit ..." << std::endl;
    }

    pthread_mutex_destroy( &mtx );          // 销毁锁
    pthread_cond_destroy( &cond );          // 销毁条件变量

    return 0;
}